/*
 * Copyright 2008 Zoundry LLC, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.zoundry.gaedt.core.models.cspec;

import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;

import org.zoundry.gaedt.core.models.IZGaeModelMutatorProvider;
import org.zoundry.gaedt.core.models.ZGaeModel;
import org.zoundry.gaedt.core.util.ZGaeUtil;


/**
 * Mutator provider used when reading in a .cspec file.
 */
public class ZGaeCSpecMutatorProvider implements IZGaeModelMutatorProvider
{
    /**
     * Creates a key to use in the map.
     * 
     * @param aModelClass
     * @param aAttributeName
     */
    private static final String createMutatorKeyForAttr(Class aModelClass, QName aAttributeName)
    {
        String ns = aAttributeName.getNamespaceURI() == null ? "" : aAttributeName.getNamespaceURI();
        String localPart = aAttributeName.getLocalPart();
        String modelName = aModelClass.getName();
        return MessageFormat.format("attr:{0}:{1}:{2}", modelName, ns, localPart);
    }

    /**
     * Creates a key to use in the map.
     *
     * @param aParentModelClass
     * @param aChildModelClass
     */
    private static final String createMutatorKeyForChild(Class aParentModelClass, Class aChildModelClass)
    {
        return MessageFormat.format("child:{0}:{1}", aParentModelClass.getName(), aChildModelClass.getName());
    }

    /**
     * Creates a key to use in the map.
     *
     * @param aModelClass
     */
    private static final String createMutatorKeyForValue(Class aModelClass)
    {
        return "value:" + aModelClass.getName();
    }

    /** The map of mutator key to mutator method. */
    private Map<String, Method> mMutatorKeyToMethodMap = new HashMap<String, Method>();

    /**
     * C'tor.
     */
    public ZGaeCSpecMutatorProvider()
    {
        try
        {
            initMap();
        }
        catch (Exception e)
        {
            ZGaeUtil.logError(e);
        }
    }

    /**
     * Initializes the mutator key to method map.
     */
    private void initMap() throws Exception
    {
        // First, add mappings for the 'controllers' element
        String key = createMutatorKeyForAttr(ZGaeControllersModel.class, new QName("", "debug"));
        getMutatorKeyToMethodMap().put(key, ZGaeControllersModel.class.getMethod("setDebug", boolean.class));
        key = createMutatorKeyForChild(ZGaeControllersModel.class, ZGaeControllerModel.class);
        getMutatorKeyToMethodMap().put(key, ZGaeControllersModel.class.getMethod("addController", ZGaeControllerModel.class));
        
        // Now, add mappings for the 'controller' element
        key = createMutatorKeyForAttr(ZGaeControllerModel.class, new QName("", "path"));
        getMutatorKeyToMethodMap().put(key, ZGaeControllerModel.class.getMethod("setPath", String.class));
        key = createMutatorKeyForAttr(ZGaeControllerModel.class, new QName("", "pattern"));
        getMutatorKeyToMethodMap().put(key, ZGaeControllerModel.class.getMethod("setPattern", String.class));
        key = createMutatorKeyForAttr(ZGaeControllerModel.class, new QName("", "class"));
        getMutatorKeyToMethodMap().put(key, ZGaeControllerModel.class.getMethod("setClassname", String.class));
        
    }

    /**
     * @see org.zoundry.gaedt.core.models.IZGaeModelMutatorProvider#getMutatorForAttribute(org.zoundry.gaedt.core.models.ZGaeModel,
     *      javax.xml.namespace.QName, java.lang.Object)
     */
    public Method getMutatorForAttribute(ZGaeModel aModel, QName aName, Object aValue)
    {
        String mapKey = createMutatorKeyForAttr(aModel.getClass(), aName);
        return getMutator(mapKey);
    }

    /**
     * @see org.zoundry.gaedt.core.models.IZGaeModelMutatorProvider#getMutatorForChild(org.zoundry.gaedt.core.models.ZGaeModel, javax.xml.namespace.QName, org.zoundry.gaedt.core.models.ZGaeModel)
     */
    public Method getMutatorForChild(ZGaeModel aModel, QName aElementName, ZGaeModel aParentModel)
    {
        String mapKey = createMutatorKeyForChild(aParentModel.getClass(), aModel.getClass());
        return getMutator(mapKey);
    }

    /**
     * @see org.zoundry.gaedt.core.models.IZGaeModelMutatorProvider#getMutatorForElementValue(org.zoundry.gaedt.core.models.ZGaeModel, java.lang.Object)
     */
    public Method getMutatorForElementValue(ZGaeModel aModel, Object aModelValue)
    {
        String mapKey = createMutatorKeyForValue(aModel.getClass());
        return getMutator(mapKey);
    }

    /**
     * Gets a mutator method from the map.
     * 
     * @param aMapKey
     */
    private Method getMutator(String aMapKey)
    {
        Method method = getMutatorKeyToMethodMap().get(aMapKey);
        return method;
    }

    /**
     * @return the mutatorKeyToMethodMap
     */
    protected Map<String, Method> getMutatorKeyToMethodMap()
    {
        return mMutatorKeyToMethodMap;
    }

    /**
     * @param aMutatorKeyToMethodMap the mutatorKeyToMethodMap to set
     */
    protected void setMutatorKeyToMethodMap(Map<String, Method> aMutatorKeyToMethodMap)
    {
        mMutatorKeyToMethodMap = aMutatorKeyToMethodMap;
    }
}
